package org.mysterylab.utopiaframework.commons.compass.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.compass.spring.web.mvc.CompassSearchController;
import org.mysterylab.utopiaframework.commons.compass.command.AdvancedSearchCommand;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;

/**
 * 高级搜索的控制器, 继承于 {@link CompassSearchController}.
 * 如果还需要增加更多的搜索条件, 继承本类, 并重载 {@link #onSetUpCommand(AdvancedSearchCommand, StringBuffer)
 * 及 {@link #referenceData(AdvancedSearchCommand)} 方法. 在 Spring  配置文件中可配置如下:
 * <pre>
 * {@code
 * }
 * </pre>
 * 另外, 加入你现在重载了一个新的高级搜索命令(比如 {@link AdvancedSearchCommand} 中提及的
 * BookSearchCommand.java), 那么就需要继承该 Controler 来编写对应的 BookSearchController, 比如:
 * <pre>
 *  public class BookSearchController extends AdvancedSearchController {
 *  
 *      private BookDao bookDao;
 *      
 *      private CategoryDao cateogryDao;
 *      
 *      public BookSearchController() {
 *          setCommandClass(BookSearchCommand.class);
 *      }
 *      
 *      protected void onSetUpCommand(AdvancedSearchCommand command, StringBuffer sb) {
 *          BookSearchCommand bookCommand = (BookSearchCommand) command;
 *          if (StringUtils.isNotBlank((bookCommand.getCategoryName()))) {
 *              // 注意这里的 "cname" 是在 Domain 类中声明
 *              sb.append(" AND cname:");
 *              sb.append(bookCommand.getCategoryName().trim());
 *              sb.append(" ");
 *          }
 *      }
 *      
 *      protected void referenceData(AdvancedSearchCommand command) {
 *          command.getReferenceData().put("categorys", categoryDao.getAll());
 *      }
 *  }
 * </pre>
 * 
 * @author zhouych
 * @see AdvancedSearchCommand
 */
public class AdvancedSearchController extends CompassSearchController {

	/**
	 * 构造方法, 重新加载新的搜索命令类 {@link AdvancedSearchCommand}.
	 */
	@SuppressWarnings("deprecation")
	public AdvancedSearchController() {
		super.setCommandClass(AdvancedSearchCommand.class);
	}

	/**
	 * 高级搜索页处理页, 处理搜索条件页及搜索结果页的显示.
	 */
	@Override
	protected ModelAndView handle(HttpServletRequest request,
			HttpServletResponse response, Object command, BindException errors)
			throws Exception {
		AdvancedSearchCommand asCommand = (AdvancedSearchCommand) command;
		asCommand = setUpCommand(asCommand);
		return super.handle(request, response, asCommand, errors);
	}

	/**
	 * 将高级搜索条件加工成符合语法的 quary 字符串.
	 * 
	 * @param command
	 * @return
	 */
	protected AdvancedSearchCommand setUpCommand(AdvancedSearchCommand command) {

		StringBuffer sb = new StringBuffer();

		if (StringUtils.isNotBlank(command.getFull())) {
			Object[] texts = splitQuery(command.getFull());
			for (int i = 0; i < texts.length; i++) {
				if (StringUtils.isEmpty((String) texts[i])) {
					continue;
				}
				sb.append(texts[i]);
				if (i != texts.length - 1) {
					sb.append(" AND ");
				}
			}
		}

		if (StringUtils.isNotBlank(command.getAnyone())) {
			sb.append(" ");
			sb.append(command.getAnyone());
			sb.append(" ");
		}

		if (StringUtils.isNotBlank(command.getExclude())) {
			Object[] texts = splitQuery(command.getExclude());
			for (Object text : texts) {
				if (StringUtils.isEmpty((String) text)) {
					continue;
				}
				sb.append(" -");
				sb.append(text);
			}
		}
		// 最后调用子类的扩展点
		onSetUpCommand(command, sb);

		if (StringUtils.isNotEmpty(sb.toString())) {
			command.setQuery(sb.toString());
		}

		if (command.getPageSize() != null) {
			this.setPageSize(command.getPageSize());
		}
		
		// 调用子类函数, 将比如图书分类 Category 这样的对象放入 command 中供查询条件页使用
		referenceData(command);

		return command;
	}

	/**
	 * 分割查询字符串成数组，保留""字符 eg. "aa bb" cc => String[]{"aa bb",cc} aa bb cc =>
	 * String[]{aa, bb,cc}
	 */
	protected Object[] splitQuery(String query) {
		
		List<String> list = new ArrayList<String>();
		Pattern pattern = Pattern
				.compile("\\s*(\\u0022\\s*\\S+.*\\S+\\s*\\u0022)|(\\S+)\\s*");

		Matcher matcher = pattern.matcher(query);

		while (matcher.find()) {
			String key = matcher.group(1) != null ? matcher.group(1) : matcher.group(2);
			list.add(key);
		}
		return list.toArray();
	}

	/**
	 * 进一步加工条件的回调函数, 在子类重载.
	 * 
	 * @param command
	 * @param sb
	 */
	protected void onSetUpCommand(AdvancedSearchCommand command, StringBuffer sb) {
	}

	/**
	 * 将 Category 等辅助显示的数据放入 command 中的回调函数, 在子类重载.
	 * 
	 * @param command
	 */
	protected void referenceData(AdvancedSearchCommand command) {
	}
}
